#pragma once

#include <functional>
#include <iostream>
#include <cstring>
#include <string>
#include <cerrno>
#include <pthread.h>

namespace thread
{
    using namespace std;

    /*
     *外部创建线程时需要指定一个函数指针和一个参数(void *类型)
     *Thrad类将该回调函数用包装器包装
    */
    class Thread
    {
    public:
        typedef function<void *(void *)> func_t;
    public:
        Thread()
        {
            char nameBuffer[1024];
            snprintf(nameBuffer,sizeof(nameBuffer),"thread %d",_threadId++);
            _name = nameBuffer;
        }

        /*
         *线程的运行我们想手动控制
         *但是pthread_create指定的回调函数为void *start_routine(void *)类型
         *所以无法给pthread_create传递包装器类型，故在此函数之后定义一个静态成员函数
         *将this指针传递给该静态成员函数，在静态成员函数里面再回调包装器包装的函数
        */
        void start(const func_t& func,void *args)
        {
            _func = func;
            _args = args;
            int n = pthread_create(&_tid,nullptr,start_routine,(void *)this);
            if(n != 0)
            {
                cout << "error code:" << n << " " << strerror(n) << endl;
                exit(n);
            }
        }

        /*
         *如果该函数不是静态成员函数，那么就有一个隐藏的this指针
         *因为没有this指针，所以无法直接使用成员变量_func
         *所以我们在pthread_create()中手动传递一个this指针
        */
        static void *start_routine(void *args)
        {
            Thread *_this = static_cast<Thread *>(args);
            return _this->_func(_this->_args);
        }

        const string &thread_name()
        {
            return _name;
        }


        /*线程等待，将返回值一并带出*/
        void *join()
        {
            void *ret;
            int n = pthread_join(_tid,&ret);
            if(n != 0)
            {
                cout << "error code:" << n << " " << strerror(n) << endl;
                exit(n);
            }
            return ret;
        }
    private:
        pthread_t _tid;
        void *_args;
        func_t _func;
        string _name;
        static size_t _threadId;
    };
    size_t Thread::_threadId = 1;
}// the namespace ly ends here